package net.homeip.jcperera.nu.core.msg;

import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.logging.Level;

import javax.faces.application.FacesMessage;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.context.FacesContext;

import net.homeip.jcperera.nu.core.CoreBase;
import net.homeip.jcperera.nu.core.utils.DateUtil;

/**
 * A simple Log Line to hold information about something logged to the {@link Logger}
 * 
 * @name Log Line class
 * @author julio.c.perera@gmail.com
 * @application nu
 * @since 0.1.0.0
 */
public class LogLine extends CoreBase
{
    // Required to implement Serializable interface

    // CoreBase properties, for easy use from other components, as well as logging
    public static final int    runtimeLevel  = 0;
    public static final String moduleName    = "core";
    public static final String componentName = "nu_core_msg_log_line";

    public static final String logDateFormat = "yyyy-MM-dd HH:mm:ss";

    /**
     * The {@link Calendar} of the Log Line (when was generated).
     */
    private Calendar           date          = Calendar.getInstance();

    /**
     * The {@link Level} of the Log Line (according to Java Logging framework)
     */
    private Level              level         = Level.INFO;

    /**
     * The contents of the line (including substitution parameters)
     */
    private String             line;

    /**
     * Substitution parameters of this Log Line
     */
    private Object[]           params;

    LogLine(String line)
    {
        this.line = line;
    }

    LogLine(String line, Object[] params)
    {
        this.line = line;
        this.params = params;
    }

    LogLine(Level level, String line, Object[] params)
    {
        this.level = level;
        this.line = line;
        this.params = params;
    }

    LogLine(Calendar date, Level level, String line, Object[] params)
    {
        this.date = date;
        this.level = level;
        this.line = line;
        this.params = params;
    }

    public Calendar getDate()
    {
        return date;
    }

    public void setDate(Calendar date)
    {
        this.date = date;
    }

    public Level getLevel()
    {
        return level;
    }

    public void setLevel(Level level)
    {
        this.level = level;
    }

    public String getLine()
    {
        return line;
    }

    public void setLine(String line)
    {
        this.line = line;
    }

    public Object[] getParams()
    {
        return params;
    }

    public void setParams(Object[] params)
    {
        this.params = params;
    }

    /**
     * Gets the {@linkplain FacesMessage} severity equivalent to the current {@link Level} of this Log Line
     * 
     * @return The equivalent {@linkplain FacesMessage} severity
     */
    public Severity getFacesMessageSeverity()
    {
        Severity result = FacesMessage.SEVERITY_INFO;
        if (level.intValue() >= Level.SEVERE.intValue()) result = FacesMessage.SEVERITY_ERROR;
        else if (level.intValue() >= Level.WARNING.intValue()) result = FacesMessage.SEVERITY_WARN;
        else if (level.intValue() >= Level.INFO.intValue()) result = FacesMessage.SEVERITY_INFO;
        return result;
    }

    /**
     * Returns a {@link String} representation of the {@link Calendar}, formatted according to the pattern: 'yyyy-MM-dd
     * HH:mm:ss', please see {@link SimpleDateFormat} for more information.
     * 
     * @return The formatted {@link String} representation
     */
    public String dateToString()
    {
        return DateUtil.getUsingSimpleDateFormat(date, logDateFormat);
    }

    /**
     * Returns the {@code line} appropriately formatted and substituted using the {@code params}. In other words, all positional and
     * substitution parameters are processed in the returned {@link String}. No processing is made is there is no parameters specified.
     *  
     * @return The formatted {@link String} (if applies)
     */
    public String getFormattedLine()
    {
        if (params == null) return line;
        else return MessageFormat.format(line, params);
    }
    
    /**
     * Returns a {@link String} representation of this Message, including the {@link Date} formatted according to the
     * pattern: 'yyyy-MM-dd HH:mm:ss', please see {@link SimpleDateFormat} for more information, also all positional and
     * substitution parameters are processed in the returned {@link String}
     * 
     * @return The {@link String} representation
     */
    public String toString()
    {
        return dateToString() + " - " + getFormattedLine();
    }

    /**
     * Adds the Message to the FacesContext (in case you are using JSF FacesContext)
     * 
     * @param facesMessages
     *            The facesMessage Context
     */
    public void addMessageToFacesContext(FacesContext facesContext)
    {
        facesContext.addMessage(null, new FacesMessage(getFacesMessageSeverity(), dateToString(), getFormattedLine()));
    }
    
    /**
     * Adds the Message to the FacesContext (in case you are using JSF FacesContext) using the specified {@code clientId}
     * 
     * @see FacesContext#addMessage(String, FacesMessage)
     * @param clientId The clientId of the specific component instance
     * @param facesContext the {@link FacesContext}
     */
    public void addMessageToFacesContext(String clientId, FacesContext facesContext)
    {
        facesContext.addMessage(clientId, new FacesMessage(getFacesMessageSeverity(), dateToString(), getFormattedLine()));
    }
}
